package com.clock.scratch;

import com.clock.scratch.factory.PixelMapFactory;
import com.clock.scratch.util.LogUtil;
import com.clock.scratch.util.Util;
import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.render.*;
import ohos.agp.utils.Color;
import ohos.agp.utils.Rect;
import ohos.app.Context;
import ohos.app.dispatcher.TaskDispatcher;
import ohos.app.dispatcher.task.TaskPriority;
import ohos.media.image.PixelMap;
import ohos.multimodalinput.event.TouchEvent;


public class ScratchView extends Component implements Component.EstimateSizeListener, Component.DrawTask {

    public final static String ATTR_MASK_COLOR = "sv_mask_color";
    public final static String ATTR_WATER_MARK = "sv_water_mark";
    public final static String ATTR_ERASE_SIZE = "sv_erase_size";
    public final static String ATTR_MAX_PERCENT = "sv_max_percent";
    public final static String ATTR_VERTICAL_REPEAT = "sv_vertical_repeat_count";
    public final static String ATTR_HORIZONTAL_REPEAT = "sv_horizontal_repeat_count";
    /**
     * 最小的橡皮擦尺寸大小
     */
    private final static float DEFAULT_ERASER_SIZE = 60f;
    /**
     * 默认蒙板的颜色
     */
    private final static int DEFAULT_MASKER_COLOR = 0xffcccccc;
    /**
     * 默认擦除比例
     */
    private final static int DEFAULT_PERCENT = 70;
    /**
     * 最大擦除比例
     */
    private final static int MAX_PERCENT = 100;

    /**
     * 遮罩 Paint
     */
    private Paint mMaskPaint;
    /**
     * 产生遮罩效果的 PixelMap
     */
    private PixelMap mMaskPixelMap;
    /**
     * 绘制遮罩的 Canvas
     */
    private Canvas mMaskCanvas;
    /**
     * 普通绘制 PixelMap 用的 Paint
     */
    private Paint mBitmapPaint;
    /**
     * 水印
     */
    private PixelMap mWatermark;
    /**
     * 橡皮檫画笔
     */
    private Paint mErasePaint;
    /**
     * 擦除轨迹
     */
    private Path mErasePath;
    /**
     * 擦除效果起始点的x坐标
     */
    private float mStartX;
    /**
     * 擦除效果起始点的y坐标
     */
    private float mStartY;
    /**
     * 最小滑动距离
     */
    private int mTouchSlop;
    /**
     * 完成擦除
     */
    private boolean mIsCompleted = false;
    /**
     * 最大擦除比例
     */
    private int mMaxPercent = DEFAULT_PERCENT;
    /**
     * 当前擦除比例
     */
    private int mPercent = 0;
    /**
     * 存放蒙层像素信息的数组
     */
    private int[] mPixels;

    private int watermarkResId = -1;

    private int width,height;

    private int horizontalRepeatCount = 16, verticalRepeatCount = 16;

    private EraseStatusListener mEraseStatusListener;

    private TaskDispatcher uiTaskDispatcher;
    private TaskDispatcher taskDispatcher;

    public ScratchView(Context context) {
        super(context);
        init(context, null);
    }

    public ScratchView(Context context, AttrSet attrSet) {
        super(context, attrSet);
        init(context, attrSet);
    }

    public ScratchView(Context context, AttrSet attrSet, String styleName) {
        super(context, attrSet, styleName);
        init(context, attrSet);
    }


    private void init(Context context, AttrSet attrSet) {
        setEstimateSizeListener(this);
        addDrawTask(this);
        setTouchEventListener(touchEventListener);
        taskDispatcher = context.createSerialTaskDispatcher("serialTaskDispatcher", TaskPriority.DEFAULT);
        uiTaskDispatcher = context.getUITaskDispatcher();
        int maskColor = DEFAULT_MASKER_COLOR;
        float eraseSize = DEFAULT_ERASER_SIZE;
        if (attrSet!=null){
            boolean present = attrSet.getAttr(ATTR_MASK_COLOR).isPresent();
            maskColor = present ? Util.getColorFromString(context, attrSet.getAttr(ATTR_MASK_COLOR).get().getStringValue(), DEFAULT_MASKER_COLOR) : DEFAULT_MASKER_COLOR;
            present = attrSet.getAttr(ATTR_WATER_MARK).isPresent();
            watermarkResId = present ? Util.toIntegerValue(attrSet.getAttr(ATTR_WATER_MARK).get().getStringValue()) : -1;
            present = attrSet.getAttr(ATTR_ERASE_SIZE).isPresent();
            eraseSize = present ? attrSet.getAttr(ATTR_ERASE_SIZE).get().getFloatValue() : DEFAULT_ERASER_SIZE;
            present = attrSet.getAttr(ATTR_MAX_PERCENT).isPresent();
            mMaxPercent = present ? attrSet.getAttr(ATTR_MAX_PERCENT).get().getIntegerValue() : DEFAULT_PERCENT;
            present = attrSet.getAttr(ATTR_VERTICAL_REPEAT).isPresent();
            verticalRepeatCount = present ? attrSet.getAttr(ATTR_VERTICAL_REPEAT).get().getIntegerValue() : 16;
            present = attrSet.getAttr(ATTR_HORIZONTAL_REPEAT).isPresent();
            horizontalRepeatCount = present ? attrSet.getAttr(ATTR_HORIZONTAL_REPEAT).get().getIntegerValue() : 16;
        }
        mMaskPaint = new Paint();
        mMaskPaint.setAntiAlias(true);
        mMaskPaint.setDither(true);
        mMaskPaint.setColor(new Color(maskColor));

        mBitmapPaint = new Paint();
        mBitmapPaint.setAntiAlias(true);
        mBitmapPaint.setDither(true);

        mErasePaint = new Paint();
        mErasePaint.setAntiAlias(true);
        mErasePaint.setDither(true);
        mErasePaint.setBlendMode(BlendMode.CLEAR);
        mErasePaint.setStyle(Paint.Style.STROKE_STYLE);
        mErasePaint.setStrokeCap(Paint.StrokeCap.ROUND_CAP);
        setEraserSize(eraseSize);

        mErasePath = new Path();

        mTouchSlop = (int) eraseSize/2;
    }


    /**
     * 设置橡皮檫尺寸大小（默认大小是 60）
     *
     * @param eraserSize 橡皮檫尺寸大小
     */
    public void setEraserSize(float eraserSize) {
        mErasePaint.setStrokeWidth(eraserSize);
        mTouchSlop = (int) eraserSize/2;
    }

    /**
     * 设置蒙板颜色
     *
     * @param color 十六进制颜色值，如：0xffff0000（不透明的红色）
     */
    public void setMaskColor(int color) {
        mMaskPaint.setColor(new Color(color));
        reset();
    }

    /**
     * 设置最大的擦除比例
     *
     * @param max 大于0，小于等于100
     */
    public void setMaxPercent(int max) {
        if (max > MAX_PERCENT || max <= 0) {
            return;
        }
        this.mMaxPercent = max;
    }

    @Override
    public void onDraw(Component component, Canvas canvas) {
        canvas.drawPixelMapHolder(new PixelMapHolder(mMaskPixelMap), 0, 0, mBitmapPaint);//绘制图层遮罩
    }

    @Override
    public boolean onEstimateSize(int widthMeasureSpec, int heightMeasureSpec) {
        width = measureSize(widthMeasureSpec);
        height = measureSize(heightMeasureSpec);
        setEstimatedSize(EstimateSpec.getChildSizeWithMode(width, width, EstimateSpec.NOT_EXCEED),
                EstimateSpec.getChildSizeWithMode(height, height, EstimateSpec.NOT_EXCEED));
        setWatermark(watermarkResId);
        createMasker(width, height);
        return true;
    }

    private final TouchEventListener touchEventListener = (component, touchEvent) -> {
        int action = touchEvent.getAction();
        LogUtil.i("x: %f, y: %f", touchEvent.getPointerPosition(0).getX(), touchEvent.getPointerPosition(0).getY());
        switch (action){
            case TouchEvent.PRIMARY_POINT_DOWN:
                startErase(touchEvent.getPointerPosition(0).getX(), touchEvent.getPointerPosition(0).getY());
                invalidate();
                return true;
            case TouchEvent.POINT_MOVE:
                erase(touchEvent.getPointerPosition(0).getX(), touchEvent.getPointerPosition(0).getY());
                invalidate();
                return true;
            case TouchEvent.PRIMARY_POINT_UP:
                stopErase();
                invalidate();
                return true;
        }

        return false;
    };


    /**
     * 创建蒙层
     *
     * @param width component width
     * @param height component height
     */
    private void createMasker(int width, int height) {
        mMaskPixelMap = PixelMapFactory.createPixelMap(0, width, height);
        mMaskCanvas = new Canvas(new Texture(mMaskPixelMap));
        Rect rect = new Rect(0, 0, width, height);
        mMaskCanvas.drawRect(rect, mMaskPaint);//绘制生成和控件大小一致的遮罩 Bitmap

        if (mWatermark != null) {
            int watermarkWidth = mWatermark.getImageInfo().size.width;
            int watermarkHeight = mWatermark.getImageInfo().size.height;
            for (int vi=0; vi<verticalRepeatCount;vi++){
                for (int hi=0; hi<horizontalRepeatCount;hi++){
                    mMaskCanvas.drawPixelMapHolder(new PixelMapHolder(mWatermark), watermarkWidth*hi, watermarkHeight*vi, mBitmapPaint);
                }
            }
        }

        mPixels = new int[width * height];

    }



    private int measureSize(int measureSpec) {
        int size = 0;
        int specMode = EstimateSpec.getMode(measureSpec);
        int specSize = EstimateSpec.getSize(measureSpec);
        if (specMode == EstimateSpec.PRECISE) {
            size = specSize;
        } else {
            if (specMode == EstimateSpec.NOT_EXCEED) {
                size = Math.min(size, specSize);
            }
        }
        return size;
    }

    /**
     * 开始擦除
     *
     * @param x point coordinate x
     * @param y point coordinate y
     */
    private void startErase(float x, float y) {
        mErasePath.reset();
        mErasePath.moveTo(x, y);
        this.mStartX = x;
        this.mStartY = y;
    }

    /**
     * 擦除
     *
     * @param x point coordinate x
     * @param y point coordinate y
     */
    private void erase(float x, float y) {
        int dx = (int) Math.abs(x - mStartX);
        int dy = (int) Math.abs(y - mStartY);
        if (dx >= mTouchSlop || dy >= mTouchSlop) {
            this.mStartX = x;
            this.mStartY = y;

            mErasePath.lineTo(x, y);
            mMaskCanvas.drawPath(mErasePath, mErasePaint);

            mErasePath.reset();
            mErasePath.moveTo(mStartX, mStartY);
        }
    }

    private void updateErasePercent(){
        //获取覆盖图层中所有的像素信息，stride用于表示一行的像素个数有多少
        mMaskPixelMap.readPixels(mPixels, 0, width, new ohos.media.image.common.Rect(0, 0, width, height));

        float erasePixelCount = 0;//擦除的像素个数
        float totalPixelCount = width * height;//总像素个数

        for (int pos = 0; pos < totalPixelCount; pos++) {
            if (mPixels[pos] == 0) {//透明的像素值为0
                erasePixelCount++;
            }
        }

        int percent = 0;
        if (erasePixelCount >= 0 && totalPixelCount > 0) {
            percent = Math.round(erasePixelCount * 100 / totalPixelCount);
            mPercent = percent;
            uiTaskDispatcher.asyncDispatch(()-> onPercentUpdate(mPercent));
        }
        boolean result = percent >= mMaxPercent;
        uiTaskDispatcher.asyncDispatch(()->{
            if (result && !mIsCompleted) {//标记擦除，并完成回调
                mIsCompleted = true;
                if (mEraseStatusListener != null) {
                    mEraseStatusListener.onCompleted(ScratchView.this);
                }
            }
        });
    }

    /**
     * 停止擦除
     */
    private void stopErase() {
        this.mStartX = 0;
        this.mStartY = 0;
        mErasePath.reset();
        taskDispatcher.syncDispatch(this::updateErasePercent);
    }

    private void onPercentUpdate(int mPercent) {
        if (mEraseStatusListener != null) {
            mEraseStatusListener.onProgress(mPercent);
        }
    }

    /**
     * 设置擦除监听器
     *
     * @param listener 监听器
     */
    public void setEraseStatusListener(EraseStatusListener listener) {
        this.mEraseStatusListener = listener;
    }

    /**
     * 设置水印图标
     *
     * @param resId 图标资源id，-1表示去除水印
     */
    public void setWatermark(int resId) {
        if (resId == -1) {
            mWatermark = null;
        } else {
            mWatermark = PixelMapFactory.createPixelMap(getContext(), resId, width/horizontalRepeatCount, height/verticalRepeatCount);
        }
        reset();
    }

    /**
     * 重置为初始状态
     */
    public void reset() {
        mIsCompleted = false;
        createMasker(width, height);
        invalidate();
        taskDispatcher.syncDispatch(this::updateErasePercent);
    }

    /**
     * 清除整个图层
     */
    public void clear() {

        mMaskPixelMap = PixelMapFactory.createPixelMap(0, width, height);
        mMaskCanvas = new Canvas(new Texture(mMaskPixelMap));
        Rect rect = new Rect(0, 0, width, height);
        mMaskCanvas.drawRect(rect, mErasePaint);
        invalidate();

        taskDispatcher.syncDispatch(this::updateErasePercent);
    }




    /**
     * 擦除状态监听器
     */
    public interface EraseStatusListener {

        /**
         * 擦除进度
         *
         * @param percent 进度值，大于0，小于等于100；
         */
        void onProgress(int percent);

        /**
         * 擦除完成回调函数
         *
         * @param component component
         */
        void onCompleted(Component component);
    }
}
